package service

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v4"
	"net/http"
	"time"
	"zsc-boot/app/system_layer/model"
	"zsc-boot/core/orm"
	"zsc-boot/core/web"
)

const headerTokenKey = "Wm-Token"

// JWTMiddleware jwt 自定义中间件
func JWTMiddleware(ctx *gin.Context) {
	token := ctx.GetHeader(headerTokenKey)
	claims, err := GetClaims(token)
	if err != nil {
		ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
			"code": http.StatusForbidden,
			"err":  err.Error(),
			"msg":  "token过期",
		})
		return
	}
	var userInfo model.ServiceUser
	if err = orm.GetDb().Model(model.ServiceUser{}).Preload("Role").Where("id = ?", claims.ID).
		Find(&userInfo).Error; err != nil {
		web.FailResponse(ctx, err, "服务异常")
		return
	}
	if time.Time(userInfo.Role.UpdatedAt).Add(-time.Second).After(time.Time(claims.RoleDate)) {
		ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
			"code": http.StatusForbidden,
			"err":  "",
			"msg":  "token过期",
		})
		return
	}
	if userInfo.Password != claims.Password {
		ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
			"code": http.StatusForbidden,
			"err":  "",
			"msg":  "token过期",
		})
		return
	}

	ctx.Set(headerTokenKey, claims)
	ctx.Next()
}

// NewToken 创建一个token
func NewToken(userId uint, password string, roleDate orm.LocalTime) (string, error) {
	var tmp BaseClaims
	tmp.ID = userId
	tmp.Password = password
	tmp.RoleDate = roleDate
	tmp.ExpiresAt = jwt.NewNumericDate(time.Now().Add(30 * 24 * time.Hour))
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, tmp)
	return token.SignedString([]byte("zsc-boot")) //加盐
}

// GetClaims 获取claims
func GetClaims(tokenString string) (claims BaseClaims, err error) {
	token, err := jwt.ParseWithClaims(tokenString, &BaseClaims{}, func(token *jwt.Token) (i interface{}, e error) {
		return []byte("zsc-boot"), nil
	})
	if err != nil {
		return
	}
	cla, _ := token.Claims.(*BaseClaims)
	var userInfo model.ServiceUserSimple
	if err = orm.GetDb().Where("id = ? and is_active = ?", cla.ID, true).First(&userInfo).Error; err != nil {
		return *cla, errors.New("用户状态异常，可能已离职或删除")
	}
	return *cla, err
}

// GetUserID 获取用户信息 会查询数据库
func GetUserID(ctx *gin.Context) int {
	token, _ := ctx.Get(headerTokenKey)
	tokenClaims, _ := token.(BaseClaims)
	return int(tokenClaims.ID)
}

type BaseClaims struct {
	ID       uint          `json:"Id"` // 用户ID
	Password string        `json:"Password"`
	RoleDate orm.LocalTime `json:"RoleDate"`
	jwt.RegisteredClaims
}
